package org.biogroovy.io.sulab;

import groovy.json.JsonSlurper
import groovy.util.logging.Slf4j

import org.biogroovy.conf.BioGroovyConfig
import org.biogroovy.io.AbsJsonSeqFetcher
import org.biogroovy.io.IFetcher;
import org.biogroovy.models.Article
import org.biogroovy.models.Gene
import org.biogroovy.net.URLMap

/**
 * This class is responsible for parsing the MyGene.info JSON response.
 * and returning a gene.
 */
@Slf4j
public class MyGeneInfoFetcher extends AbsJsonSeqFetcher<Gene> {
	
	private static final String DATABASE_NAME="mygeneinfo";
	private static final String URL_TEMPLATE = 'http://mygene.info/v2/query?q=entrezgene:id';
	
	private Map<String, String> paramMap = ["fields":"all", "entrezonly":"true"];
	
	private String email = null;
	
	
	/** 
	 * Constructor
	 */
	public MyGeneInfoFetcher(){
		this.databaseName=DATABASE_NAME;
		init();
	}
	
	/**
	 * Constructor
	 * @param paramMap a map of parameters
	 */
	public MyGeneInfoFetcher(Map<String, String> paramMap){
		this();
		this.paramMap.putAll(paramMap);
		init();
	}
	
	
	private void init() {
		ConfigObject conf = BioGroovyConfig.getConfig()
		this.email = conf.mygeneinfo.email
	}

	
	@Override
	public Gene fetch(String id) throws IOException {
		
		URL url = getUrl(id, null);
		println "url: ${url.toString()}"
		Gene gene = null;
		try {
		 gene = read(url.openStream())
		}catch (Exception ex) {
			log.error("Unable to retrieve gene using URL: " + url.toString())
			throw new IOException(ex)
		}
		
		return gene;
	}

	@Override
	public URL getUrl(String id, Map<String, String> params) {
		String url = URL_TEMPLATE.replace("id", id)
		Map<String, String> map = [email:this.email]
		map.putAll(paramMap)
		if (params != null) {
			map.putAll(params)
		}
		URLMap urlMap = new URLMap(url, map);
		return new URL(urlMap.toString());
	}



	@Override
	public List<Gene> fetchAll(String id) throws IOException {
		
		String[] idArray = id.split(",")	
		
		Gene gene = null;
		List<Gene> geneList = new ArrayList<>();
		idArray.each{String currId ->
			gene = fetch(currId.trim());
			geneList.add(gene)
		}
		
		return geneList;
	}	
	
	@Override
	public void parse(Gene pojo, Map jsonMap) {
		super.parse(pojo, jsonMap)
		parseGeneRifs(pojo, jsonMap);
		parseEnsemblIds(pojo, jsonMap)
		parseRefSeqs(pojo, jsonMap)
		parsePathways(pojo, jsonMap)
	}
	
	
	
	@Override
	protected void parseEnsemblIds(Gene gene, Map jsonMap) {
		gene.references.put("ensembl-gene", jsonMap?.ensembl?.gene)
	}

	/**
	 * This method is responsible for mapping the GeneRIF articles
	 * into the gene object.
	 * @param gene
	 * @param jsonMap
	 */
	protected void parseGeneRifs(gene, jsonMap) {
		jsonMap.generif.each{it ->
			gene.articles.add(new Article(title:it.text, pubmedId:it.pubmed));
		}
	}

	@Override
	protected void parseRefSeqs(Gene gene, Map jsonMap) {
		gene.refSeqAcc = jsonMap.refseq.genomic.join(",");
	}

	@Override
	public Gene read(InputStream inputStream) throws IOException {
		JsonSlurper slurper = new JsonSlurper();
		Map jsonMap = (Map)slurper.parse(inputStream)
		Gene gene = new Gene();
		
		parse(gene, jsonMap.hits[0]);
		
		return gene;
	}

	@Override
	public List<Gene> readList(InputStream inputStream) throws IOException {
		JsonSlurper slurper = new JsonSlurper();
		Map jsonMap = (Map)slurper.parse(inputStream)
		
		List<Gene> geneList = new ArrayList<>();
		jsonMap.hits { Map currMap ->
			Gene gene = new Gene();	
			parse(gene, currMap);
			geneList.add(gene)
		}
		
		return gene;
	}

	@Override
	public IFetcher<Gene> getNewInstance() {
		return new MyGeneInfoFetcher();
	}


}
